<?php

require_once 'ZLib/Object.php';
require_once 'ZLib/Exceptions/FileException.php';

define('ZLIB_FILE_DEFAULT_PERMS_ON_FILE_CREATION', 0777);

/**
 * @license GPL v.3
 * @author Andrei Ermicioi (andrei.ermicioi@gmail.com)
 */
class ZLib_File extends ZLib_Object {
	
	private $filename;

	public function __construct($file) {
		if ($file instanceof ZLib_File) {
			$file = $file->getAbsolutePath();
		}
		
		if (!file_exists($file)) {
			throw new ZLib_Exceptions_FileException('No such file');
		}
		
		$this->filename = realpath((string) $file);
	}
	
	public function copy($destination) {
		if ($destination instanceof ZLib_File) {
			$destination = $destination->getAbsolutePath();
		}
		
		if (is_dir($destination)) {
			$destination .= '/'. $this->getName();
		}
		
		if (!file_exists(dirname($destination))) {	
			throw new ZLib_Exceptions_FileException('No destination directory');
		}
		
		if (is_file($this->filename)) {
			$this->copyFile($this->filename, $destination);
		} else {
			$this->copyDirectory($this->filename, $destination);
		}
		
		return new ZLib_File($destination);
	}
	
	public function move($destination) {
		if ($destination instanceof ZLib_File) {
			$destination = $destination->getAbsolutePath();
		}
		
		if (is_dir($destination)) {
			$destination .= '/'. $this->getName();
		}
		
		if (!file_exists(dirname($destination))) {
			throw new ZLib_Exceptions_FileException('No destination directory');
		}

		if (!rename($this->filename, $destination)) {
			throw new ZLib_Exceptions_FileException('Can not move');
		}
		
		return new ZLib_File($destination);
	}
	
	public function remove() {
		if (is_file($this->filename)) {
			$this->removeFile($this->filename);
		} else {
			$this->removeDirectory($this->filename);
		}
	}
	
	public function chmod($mode) {
		if (!chmod($this->filename, $mode)) {
			throw new ZLib_Exceptions_FileException('Can not chmod');
		}
	}
	
	public function getAbsolutePath() {
		return $this->filename;
	}
	
	public function getName() {
		return basename($this->filename);
	}
	
	public function getExtension($source) {
		$basename = basename($this->filename);
		$pos = strripos($basename, '.');
		return substr($basename, $pos + 1);
	}
	
	public function getNameWithoutExtension() {
		$basename = basename($this->filename);
		$pos = strripos($basename, '.');
		return substr($basename, 0, $pos);
	}
	
	public function isReadable() {
		return is_readable($this->filename);
	}

	public function isWritable() {
		return is_writable($this->filename);
	}

	public function isExecutable() {
		return is_executable($this->filename);
	}

	public function isFile() {
		return is_file($this->filename);
	}

	public function isDirectory() {
		return is_dir($this->filename);
	}
	
	public static function exist($source) {
		return file_exists($source);
	}
	
	public static function mkdir($dirname, $recursive = FALSE) {
		if (file_exists($dirname)) {
			throw new ZLib_Exceptions_FileException('Directory allready exists');
		}

		if (!mkdir($dirname, ZLIB_FILE_DEFAULT_PERMS_ON_FILE_CREATION, $recursive)) {
			throw new ZLib_Exceptions_FileException('Can not create directory');
		}
		
		return new ZLib_File($dirname);
	}
	
	private function copyFile($source, $destination) {
		if (!copy($source, $destination)) {
			throw new ZLib_Exceptions_FileException('Can not copy');
		}
	}
	
	private function copyDirectory($source, $destination) {
		self::mkdir($destination);

		$content = $this->getDirectoryContent($source);
		
		foreach ($content as $c) {
			$c_source = $source . '/' . $c;
			$c_destination = $destination . '/' . $c;

			if (is_dir($c_source)) {
				$this->copyDirectory($c_source, $c_destination);
			} else {
				copy($c_source, $c_destination);
			}
		}

	}
	
	private function removeFile($source) {
		if (!unlink($source)) {
			throw new ZLib_Exceptions_FileException('Can not remove');
		}
	}

	private function removeDirectory($source) {
		$content = $this->getDirectoryContent($source);
		
		foreach ($content as $c) {
			$c_source = $source . '/' . $c;

			if (is_dir($c_source)) {
				self::removeDirectory($c_source);
			} else {
				unlink($c_source);
			}
		}
		
		rmdir($source);
	}
	
	private function getDirectoryContent($dir) {
		$handle = opendir($dir);
		$content = array();

		while ($entry = readdir($handle)) {
			if ($entry == '.' || $entry == '..') {
				continue;
			}

			$content[] = $entry;
		}

		return $content;
	}
}

